"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

require("core-js/modules/es.array.from");

require("core-js/modules/es.array.iterator");

require("core-js/modules/es.array.join");

require("core-js/modules/es.array.map");

require("core-js/modules/es.array.reduce");

require("core-js/modules/es.array.splice");

require("core-js/modules/es.array-buffer.slice");

require("core-js/modules/es.object.keys");

require("core-js/modules/es.object.to-string");

require("core-js/modules/es.promise");

require("core-js/modules/es.string.iterator");

require("core-js/modules/es.typed-array.uint8-array");

require("core-js/modules/es.typed-array.copy-within");

require("core-js/modules/es.typed-array.every");

require("core-js/modules/es.typed-array.fill");

require("core-js/modules/es.typed-array.filter");

require("core-js/modules/es.typed-array.find");

require("core-js/modules/es.typed-array.find-index");

require("core-js/modules/es.typed-array.for-each");

require("core-js/modules/es.typed-array.includes");

require("core-js/modules/es.typed-array.index-of");

require("core-js/modules/es.typed-array.iterator");

require("core-js/modules/es.typed-array.join");

require("core-js/modules/es.typed-array.last-index-of");

require("core-js/modules/es.typed-array.map");

require("core-js/modules/es.typed-array.reduce");

require("core-js/modules/es.typed-array.reduce-right");

require("core-js/modules/es.typed-array.reverse");

require("core-js/modules/es.typed-array.set");

require("core-js/modules/es.typed-array.slice");

require("core-js/modules/es.typed-array.some");

require("core-js/modules/es.typed-array.sort");

require("core-js/modules/es.typed-array.subarray");

require("core-js/modules/es.typed-array.to-locale-string");

require("core-js/modules/es.typed-array.to-string");

require("core-js/modules/web.dom-collections.iterator");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.readBits = exports.readArray = exports.readUnsigned = exports.readString = exports.peekBytes = exports.readBytes = exports.peekByte = exports.readByte = exports.buildStream = exports.buildCustomLoader = exports.buildLoader = void 0;

var _ioController = _interopRequireDefault(require("../io/io-controller"));

// Default stream and parsers for Uint8TypedArray data type

/**
 * options.url url
 * options.loaderType xhr|fetch
 * options.chunkSize 200 (kb)
 */
var buildLoader = function buildLoader(options) {
  var _buffers = null;
  var error = null;
  var done = false; // 编译后的async性能较差，直接使用promise

  var ioc = new _ioController.default({
    url: options.url
  }, {
    loaderType: options.loaderType,
    chunkSize: options.chunkSize,
    stashInitialSize: 20,
    enableStashBuffer: false,
    seekType: 'range'
  });

  function checkBuffer(pos) {
    if (error) {
      console.error(error);
      return Promise.reject(new Error(error.message));
    }

    if (pos >= bufferLength()) {
      if (!done) {
        return sleep(30).then(function () {
          return checkBuffer(pos);
        });
      }
    }

    return Promise.resolve();
  }

  function bufferLength() {
    return _buffers.reduce(function (counter, buffer) {
      return counter + _buffers.length;
    }, 0);
  }

  function sleep(ms) {
    return new Promise(function (o) {
      return setTimeout(o, ms);
    });
  }

  return buildCustomLoader({
    load: function load(buffers) {
      _buffers = buffers;

      ioc._onDataArrival = function (chunk, byteStart) {
        buffers.push(new Uint8Array(chunk));
      };

      ioc._onError = function (t, e) {
        error = new Error(t + ' - ' + JSON.stringify(e));
      };

      ioc._onComplete = function (e) {
        done = true;
      }; // ioc._onSeeked = null;
      // ioc._onRedirect = null;
      // ioc._onRecoveredEarlyEof = null;


      ioc.open();
    },
    check: checkBuffer
  });
};
/**
 * options.data
 */


exports.buildLoader = buildLoader;

var buildCustomLoader = function buildCustomLoader(options) {
  var buffers = [];
  var readingBuffer = new Uint8Array([]);
  var pos = 0; // 编译后的async性能较差，直接使用promise

  options.load(buffers);

  function checkBuffer(len) {
    return options.check(pos + len);
  }

  var that = {
    readByte: function readByte() {
      return checkBuffer(1).then(function () {
        if (pos >= readingBuffer.length) {
          readingBuffer = buffers.splice(0, 1)[0] || [];
          pos = 0;
        }

        return readingBuffer[pos++];
      });
    },
    peekByte: function peekByte(offset) {
      return checkBuffer(offset).then(function () {
        var p = pos;

        if (p >= readingBuffer.length) {
          readingBuffer = buffers.splice(0, 1)[0];
          p = 0;
        }

        return readingBuffer[p + offset];
      });
    },
    readBytes: function readBytes(len) {
      return checkBuffer(len).then(function () {
        if (pos + len < readingBuffer.length) {
          var _bytes = readingBuffer.subarray(pos, pos + len);

          pos += len;
          return _bytes;
        }

        var bytes = new Uint8Array(len);
        var readedNum = 0;

        while (buffers.length > 0 || readingBuffer.length > 0) {
          if (pos + len > readingBuffer.length) {
            var sub = readingBuffer.subarray(pos);
            bytes.set(sub, readedNum);
            readedNum += sub.length;
            len -= readedNum;
            readingBuffer = buffers.splice(0, 1)[0];
            pos = 0;

            if (!readingBuffer) {
              return Promise.reject(new Error('Unexcepted EOF'));
            }
          } else {
            bytes.set(readingBuffer.subarray(pos, pos + len), readedNum);
            pos += len;
            break;
          }
        }

        return bytes;
      });
    },
    peekBytes: function peekBytes(len) {
      return checkBuffer(len).then(function () {
        if (pos + len < readingBuffer.length) {
          return readingBuffer.subarray(pos, pos + len);
        }

        var p = pos;
        var readingB = readingBuffer;
        var buffersI = 0;
        var bytes = new Uint8Array(len);
        var readedNum = 0;

        while (buffers.length > buffersI || readingB.length > 0) {
          if (p + len > readingB.length) {
            var sub = readingB.subarray(p);
            bytes.set(sub, readedNum);
            readedNum += sub.length;
            len -= readedNum;
            readingB = buffers[buffersI++];
            p = 0;

            if (!readingB) {
              return Promise.reject(new Error('Unexcepted EOF'));
            }
          } else {
            bytes.set(readingB.subarray(p, p + len), readedNum);
            break;
          }
        }

        return bytes;
      });
    },
    abort: function abort() {
      options.abort && options.abort();
    }
  };
  return that;
};

exports.buildCustomLoader = buildCustomLoader;

var buildStream = function buildStream(loader) {
  return {
    loader: loader,
    pos: 0
  };
};

exports.buildStream = buildStream;

var readByte = function readByte() {
  return function (stream) {
    return stream.loader.readByte();
  };
};

exports.readByte = readByte;

var peekByte = function peekByte() {
  var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  return function (stream) {
    return stream.loader.peekByte(offset);
  };
};

exports.peekByte = peekByte;

var readBytes = function readBytes(length) {
  return function (stream) {
    return stream.loader.readBytes(length);
  };
};

exports.readBytes = readBytes;

var peekBytes = function peekBytes(length) {
  return function (stream) {
    return stream.loader.peekBytes(length);
  };
};

exports.peekBytes = peekBytes;

var readString = function readString(length) {
  return function (stream) {
    return readBytes(length)(stream).then(function (bytes) {
      return Array.from(bytes).map(function (value) {
        return String.fromCharCode(value);
      }).join('');
    });
  };
};

exports.readString = readString;

var readUnsigned = function readUnsigned(littleEndian) {
  return function (stream) {
    return readBytes(2)(stream).then(function (bytes) {
      return littleEndian ? (bytes[1] << 8) + bytes[0] : (bytes[0] << 8) + bytes[1];
    });
  };
};

exports.readUnsigned = readUnsigned;

var readArray = function readArray(byteSize, totalOrFunc) {
  return function (stream, result, parent) {
    var totalPromise = typeof totalOrFunc === 'function' ? totalOrFunc(stream, result, parent) : totalOrFunc;
    return Promise.resolve(totalPromise).then(function (total) {
      var parser = readBytes(byteSize);
      var arr = new Array(total);
      var promiseLoop = Promise.resolve();

      for (var i = 0; i < total; i++) {
        promiseLoop = promiseLoop.then(function (e) {
          return parser(stream);
        });
        arr[i] = promiseLoop;
      }

      return promiseLoop.then(function (e) {
        return Promise.all(arr);
      });
    });
  };
};

exports.readArray = readArray;

var subBitsTotal = function subBitsTotal(bits, startIndex, length) {
  var result = 0;

  for (var i = 0; i < length; i++) {
    result += bits[startIndex + i] && Math.pow(2, length - i - 1);
  }

  return result;
};

var readBits = function readBits(schema) {
  return function (stream) {
    return readByte()(stream).then(function (byte) {
      // convert the byte to bit array
      var bits = new Array(8);

      for (var i = 0; i < 8; i++) {
        bits[7 - i] = !!(byte & 1 << i);
      } // convert the bit array to values based on the schema


      return Object.keys(schema).reduce(function (res, key) {
        var def = schema[key];

        if (def.length) {
          res[key] = subBitsTotal(bits, def.index, def.length);
        } else {
          res[key] = bits[def.index];
        }

        return res;
      }, {});
    });
  };
};

exports.readBits = readBits;